package lk.icta.common.dao.impl;

import lk.icta.common.AppConstants;
import lk.icta.common.ErrorCodes;
import lk.icta.common.dao.PreloadableDAO;
import lk.icta.common.dao.RailwayProtectionZoneDAO;
import lk.icta.common.entity.DistrictEngineerZone;
import lk.icta.common.entity.RailwayProtectionZone;
import lk.icta.common.entity.RailwayTrack;
import lk.icta.user.entity.User;

import javax.persistence.Query;
import java.util.*;

/**
 * @author Supun Viraj Rathnayaka
 */
public class RailwayProtectionZoneDAOImpl extends BaseDAO implements RailwayProtectionZoneDAO, PreloadableDAO {
    private final Map<Integer, RailwayProtectionZone> rpZonesByPK = new HashMap<Integer, RailwayProtectionZone>();
    private final Map<Integer, Map<Integer, String>> siNames = new HashMap<Integer, Map<Integer, String>>();
    private final Map<Integer, Map<Integer, String>> enNames = new HashMap<Integer, Map<Integer, String>>();
    private final Map<Integer, Map<Integer, String>> taNames = new HashMap<Integer, Map<Integer, String>>();

    @Override
    public Map<Integer, String> getAllRailwayProtectionZonesByUserLanguage(String language, User user) {
        Map<Integer, String> result = new HashMap();
        if (AppConstants.SINHALA.equals(language)) {
            for (int i = 1; i < (AppConstants.NO_OF_RAILWAY_TRACKS + 1); i++) {
                result.putAll(getRPZoneNamesImpl(siNames, i));
            }
        } else if (AppConstants.ENGLISH.equals(language)) {
            for (int i = 1; i < (AppConstants.NO_OF_RAILWAY_TRACKS + 1); i++) {
                result.putAll(getRPZoneNamesImpl(enNames, i));
            }
        } else if (AppConstants.TAMIL.equals(language)) {
            for (int i = 1; i <(AppConstants.NO_OF_RAILWAY_TRACKS + 1); i++) {
                result.putAll(getRPZoneNamesImpl(taNames, i));
            }
        } else {
            handleException("Unsupported language : " + language, ErrorCodes.INVALID_LANGUAGE);
        }
        return result;
    }

    @Override
    public Map<Integer, String> getAllRPZoneNamesByTrackId(int trackId, String language, User user) {
        Map<Integer, String> result = null;
        if (AppConstants.SINHALA.equals(language)) {
            result = getRPZoneNamesImpl(siNames, trackId);
        } else if (AppConstants.ENGLISH.equals(language)) {
            result = getRPZoneNamesImpl(enNames, trackId);
        } else if (AppConstants.TAMIL.equals(language)) {
            result = getRPZoneNamesImpl(taNames, trackId);
        } else {
            handleException("Unsupported language : " + language, ErrorCodes.INVALID_LANGUAGE);
        }
        return result;
    }

    @Override
    public RailwayProtectionZone getRPZoneById(int i) {
        logger.debug("Loading Railway Protection Zone {}", i);
        return em.find(RailwayProtectionZone.class, i);
    }

    private Map<Integer, String> getRPZoneNamesImpl(Map<Integer, Map<Integer, String>> namesByRPZone, int trackId) {
        Map<Integer, String> dsDivisionNames = namesByRPZone.get(trackId);
        if (dsDivisionNames != null) {
            return dsDivisionNames;
        }
        logger.warn("No Railway Protection Zones found for Railway Track : {}", trackId);
        return Collections.emptyMap();
    }

    @Override
    public void preload() {
        Query query = em.createQuery("SELECT d FROM RailwayProtectionZone d order by d.enProtectionZoneName");
        List<RailwayProtectionZone> results = query.getResultList();

        Map<Integer, String> subMap = null;

        for ( RailwayProtectionZone d : results) {
            updateCache(d);
        }

        logger.debug("Loaded : {} Railway Protection Zones from the database", results.size());
    }

    private void updateCache(RailwayProtectionZone d) {
        Map<Integer, String> subMap;
        List<RailwayTrack> tracks = d.getRailwayTrack();
        int rpZoneId = d.getId();

        rpZonesByPK.put(d.getId(),d);
        for(RailwayTrack track : tracks){
            int trackId = track.getId();
            subMap = siNames.get(trackId);
            if (subMap == null) {
                subMap = new TreeMap<Integer, String>();
                siNames.put(trackId, subMap);
            }
            subMap.put(rpZoneId, d.getSiProtectionZoneName());

            subMap = enNames.get(trackId);
            if (subMap == null) {
                subMap = new TreeMap<Integer, String>();
                enNames.put(trackId, subMap);
            }
            subMap.put(rpZoneId, d.getEnProtectionZoneName());

            subMap = taNames.get(trackId);
            if (subMap == null) {
                subMap = new TreeMap<Integer, String>();
                taNames.put(trackId, subMap);
            }
            subMap.put(rpZoneId, d.getTaProtectionZoneName());
        }

    }
}
